﻿using IoTClient.Clients.Modbus;
using Polly;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ArcLightProtector.Controls
{
    public class BaseController : UserControl
    {

        public string ProtectorName { get; protected set; }
        public int CycleTime { get; private set; }

        protected byte _slaveId = 1;
        public byte SlaveId { get => _slaveId; set => _slaveId = value; }


        private CancellationTokenSource _tokenSource;


        protected ModbusRtuClient _client;


        protected List<SensorPointData> _all = new List<SensorPointData>();

        protected List<GroupPointControl> _groupControls = new List<GroupPointControl>();

        protected Dictionary<SensorPointData, SensorPointControl> _controlDic = new Dictionary<SensorPointData, SensorPointControl>();


        protected ManualResetEvent _resetEvent = new ManualResetEvent(true);

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            InitData();
            InitUI();
            this.Enabled = false;
        }

        public void AddControlDic(SensorPointData data, SensorPointControl control)
        {
            _controlDic.Add(data, control);
        }

        public void SetModbusClient(ModbusRtuClient client)
        {
            _client = client;
        }

        public void SetCycleTime(int cycleTime)
        {
            this.CycleTime = cycleTime;
        }

        protected virtual void InitData()
        {

        }


        public virtual void InitUI()
        {

        }


        public void Start()
        {
            this.Enabled = true;
            foreach (var control in _groupControls)
            {
                control.Control.SetModbusClient(_slaveId, _client);
            }

            StartCore();
            _tokenSource = new CancellationTokenSource();
            Task.Factory.StartNew(CollectData, TaskCreationOptions.LongRunning);
        }

        protected virtual void StartCore()
        {

        }

        public void Stop()
        {
            this.Enabled = false;
            if (_tokenSource == null) return;
            _tokenSource.Cancel();
            _tokenSource = null;
            _client.Close();
        }

        protected void Item_OnSettingValueBefore()
        {
            _resetEvent.Reset();
        }

        protected void Item_OnSettingValueAfter()
        {
            _resetEvent.Set();
        }



        /// <summary>
        /// 采集数据
        /// </summary>
        /// <returns></returns>
        private async Task CollectData()
        {
            while (!_tokenSource.Token.IsCancellationRequested)
            {
                //var unGroupList = _all.Where(w => w.Group == null);
                //foreach (var item in unGroupList)
                //{
                //    try
                //    {
                //        _resetEvent.WaitOne();
                //        await Policy.Handle<Exception>().RetryAsync(3).ExecuteAsync(async () =>
                //        {
                //            await CollectDataCore(item);
                //        });
                //        //_dic[item.Address].RefreshValue();
                //        var data = _groupControls.FirstOrDefault(w => w.FuncName == item.Name && w.Address == item.Address);
                //        if (data != null) data.Control.RefreshValue();
                //    }
                //    catch (Exception ex)
                //    {
                //        Console.WriteLine(ex.Message);
                //        Log.Error(ex, "");
                //    }
                //    await Task.Delay(80);
                //}
                //组读取
                //var grps = _all.Where(w => w.Group.HasValue).GroupBy(g => g.Group).ToList();
                //foreach (var group in grps)
                //{
                //    Log.Information(group.Key.ToString());
                //    var datas = group.ToList();
                //    try
                //    {
                //        _resetEvent.WaitOne();
                //        await Policy.Handle<Exception>().RetryAsync(3).ExecuteAsync(async () =>
                //        {
                //            await CollectDataCore(datas);
                //        });
                //        foreach (var d in datas)
                //        {
                //            _dic[d.Address].RefreshValue();
                //        }
                //    }
                //    catch (Exception ex)
                //    {
                //        Log.Error(ex, "");
                //    }
                //    await Task.Delay(140);
                //}

                try
                {

                    //var unGroupList = _all.Where(w => w.Group == null);
                    //foreach (var item in unGroupList)
                    //{
                    //    try
                    //    {
                    //        _resetEvent.WaitOne();
                    //        await Policy.Handle<Exception>().RetryAsync(3).ExecuteAsync(() =>
                    //        {
                    //            return Task.Run(() =>
                    //            {
                    //                CollectDataCore(item);
                    //            });
                    //        });
                    //        //_dic[item.Address].RefreshValue();
                    //        var data = _groupControls.FirstOrDefault(w => w.FuncName == item.Name && w.Address == item.Address);
                    //        if (data != null) data.Control.RefreshValue();
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        Console.WriteLine(ex.Message);
                    //        Log.Error(ex, "");
                    //    }
                    //    await Task.Delay(80);
                    //}

                    CollectDataCore();

                }
                catch (Exception ex)
                {
                    Log.Error(ex, "");
                }
                await Task.Delay(1000 * CycleTime, _tokenSource.Token);
            }
        }


        /// <summary>
        /// 刷新控件值
        /// </summary>
        /// <param name="funcName"></param>
        /// <param name="address"></param>
        protected void RefreshControlValue(string funcName, int address)
        {
            var data = _groupControls.FirstOrDefault(w => w.FuncName == funcName && w.Address == address);
            if (data != null) data.Control.RefreshValue();
        }

        protected virtual void CollectDataCore()
        {

        }


        /// <summary>
        /// 处理传感器点位数据
        /// </summary>
        /// <param name="data"></param>
        protected virtual void HandleSensorPointData(SensorPointData data)
        {
            if (data.DataType == "ushort")
            {
                var resp = _client.ReadUInt16(data.Address.ToString(), _slaveId, 3);
                var value = resp.Value;
                if (string.IsNullOrEmpty(data.Operator)) data.Value = value;
                else data.Value = ComputeValue(data, value);
            }
            //else if (data.DataType == "int")
            //{
            //    var resp = await _client.ReadHoldingRegistersAsync(_slaveId, data.Address, 2);
            //    var value = resp.CreateReader().ReadUInt32();
            //    if (string.IsNullOrEmpty(data.Operator)) data.Value = value;
            //    else data.Value = ComputeValue(data, value);
            //}
            //else if (data.DataType == "string")
            //{
            //    ushort length = 1;
            //    if (!string.IsNullOrEmpty(data.EndAddressHex))
            //    {
            //        var endAddress = Convert.ToUInt16(data.EndAddressHex, 16);
            //        length = (ushort)(endAddress - data.Address + 1);
            //    }
            //    var resp = await _client.ReadHoldingRegistersAsync(_slaveId, data.Address, length);
            //    var arr = resp.CreateReader().ToInt16s(EndianType.Big).ToArray();
            //    var sb = new StringBuilder();
            //    foreach (var value in arr)
            //    {
            //        var bytes = BitConverter.GetBytes(value);
            //        foreach (var b in bytes.Reverse())
            //        {
            //            if (b == 0) continue;
            //            sb.Append((char)b);
            //        }
            //    }
            //    data.Value = sb.ToString();
            //}
            Log.Information($"读取{data.Name} 地址:{data.AddressHex}  值:{data.Value}");
        }


        protected double ComputeValue(SensorPointData data, uint value)
        {
            if (data.Operator == "/") return value * 1.0 / data.OperationValue.Value;
            else if (data.Operator == "*") return value * 1.0 * data.OperationValue.Value;
            else if (data.Operator == "X") return value * 1.0 * data.OperationValue.Value;
            return 0;
        }


        /// <summary>
        /// 刷新控件值/
        /// </summary>
        /// <param name="list"></param>
        protected void RefreshControlValue(List<SensorPointData> list)
        {
            foreach (SensorPointData data in list)
            {
                _controlDic[data].RefreshValue();
            }
        }


        protected UInt16 GetUInt16(byte[] bytes)
        {
            return BitConverter.ToUInt16(new byte[] { bytes[1], bytes[0] }, 0);
        }


        protected List<UInt16> GetUInt16s(byte[] bytes, int count)
        {
            var list = new List<UInt16>();
            for (int i = 0; i < count; i++)
            {
                var buffer = new byte[2];
                Array.Copy(bytes, i * 2, buffer, 0, 2);
                list.Add(GetUInt16(buffer));
            }
            return list;
        }

    }
}
